package edu.ccut.saturn.component;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;

import edu.ccut.saturn.component.utils.DateUtils;
import edu.ccut.saturn.component.utils.TypeValidation;

/**
 * 数据组件的运行时实例，扩展自HashMap类型。根据数据组件生成， 数据组件中记录的字段信息以键值对的形式保存在SaturnData类型实例中。
 * 
 * @author 谷钰
 * @author 温建
 * 
 * @version 1.0 2008.09.09
 * 
 */
public class SaturnData extends HashMap<String, Object> {

	private static final String DICT_POSTFIX = "_dict";

	private static final String NUMBER_FORMAT_POSTFIX = "_number_format";

	private static final String DATETIME_FORMAT_POSTFIX = "_datetime_format";

	private static final long serialVersionUID = 1315641675855445160L;

	private String namespace;

	private String type;

	private IDataInfo dataInfo = null;

	/**
	 * 根据给定的数据组件，生成SaturnData类型实例
	 * 
	 * @param namespace
	 * @param type
	 */
	public SaturnData(String namespace, String type) {
		this.namespace = namespace;
		this.type = type;
		this.dataInfo = SaturnDataManager.getInstance().getSaturnDataInfo(
				this.namespace, this.type);

		if (this.dataInfo == null) {
			throw new IllegalArgumentException(
					"Can't find saturnData in namespace : " + this.namespace
							+ ", and type : " + this.type);
		}
	}

	/**
	 * 获得生成此数据项的数据组件的信息
	 * 
	 * @return
	 */
	public IDataInfo getSaturnDataInfo() {
		return this.dataInfo;
	}

	/**
	 * 获得命名空间
	 * 
	 * @return
	 */
	public String getNamespace() {
		return namespace;
	}

	/**
	 * 设置命名空间
	 * 
	 * @param namespace
	 */
	public void setNamespace(String namespace) {
		this.namespace = namespace;
	}

	/**
	 * 获得名称
	 * 
	 * @return
	 */
	public String getType() {
		return type;
	}

	/**
	 * 设置名称
	 * 
	 * @param type
	 */
	public void setType(String type) {
		this.type = type;
	}

	/**
	 * 给属性值赋值
	 * 
	 * @param key
	 * @param value
	 */
	public void set(String key, Object value) {
		if (value instanceof String) {
			this.put(key, ((String) value).trim());
		} else {
			this.put(key, value);
		}
	}

	/**
	 * 验证参数是否合法，如果参数和java类型不合法，首先按照平台规范进行参数类型转换，如果无法进行合理转换则抛出异常。
	 * 如果参数类型是空，则认为参数可以是任何类型
	 * 
	 * @param key
	 * @param value
	 */
	private Object validate(String key, Object value) {
		if (key != null) {
			String dataItemKey = key;

			if (key.endsWith(DICT_POSTFIX)) {
				// int index = key.lastIndexOf(DICT_POSTFIX);
				// dataItemKey = key.substring(0, index);
				return value;
			}

			IDataItem dataItem = this.dataInfo.getDataItem(dataItemKey);

			if (dataItem == null) {
				throw new IllegalArgumentException(
						"Can't find key in Saturn Data [" + this.namespace
								+ "::" + this.type + "]; the key is [" + key
								+ "]");
			}

			String javaType = dataItem.getJavaType();
			if (javaType != null && !"".equals(javaType) && value != null) {

				if (javaType.indexOf("[") > -1) {
					return value;
				}

				if (javaType.equals(value.getClass().getName())
						|| javaType.equals(value.getClass().getSimpleName())) {

					return value;

				} else {

					try {
						return TypeValidation
								.getValidTypeValue(javaType, value);

					} catch (Exception e) {
						throw new IllegalArgumentException("for the key : "
								+ dataItemKey + " in Saturn Data ["
								+ this.namespace + "::" + this.type
								+ "] need type : [" + javaType
								+ "], but the value type is : ["
								+ value.getClass().getName() + "], value is ["
								+ value + "]");
					}
				}
			}
		}

		return null;
	}

	/**
	 * 获得属性的属性值
	 */
	public Object get(Object key) {
		Object value = super.get(key);

		if (value != null) {
			return value;
		}

		return getValueFromDict(key);
	}

	private Object getValueFromDict(Object key) {
		String strKey = (String) key;
		if (strKey != null)
			if (strKey.endsWith(DICT_POSTFIX)) {
				int index = strKey.lastIndexOf(DICT_POSTFIX);
				String dataItemKey = strKey.substring(0, index);

				return this.getDictValue(dataItemKey);
			} else if (strKey.endsWith(NUMBER_FORMAT_POSTFIX)) {
				int index = strKey.lastIndexOf(NUMBER_FORMAT_POSTFIX);
				String dataItemKey = strKey.substring(0, index);

				return this.getNumberFormatValue(dataItemKey);
			} else if (strKey.endsWith(DATETIME_FORMAT_POSTFIX)) {
				int index = strKey.lastIndexOf(DATETIME_FORMAT_POSTFIX);
				String dataItemKey = strKey.substring(0, index);

				return this.getNumberFormatValue(dataItemKey);
			}
		// IDataItem dataItem = this.dataInfo.getDataItem(dataItemKey);
		//
		// if (dataItem != null) {
		// String dictTypeId = dataItem.getDictTypeId();
		//
		// if (dictTypeId != null && !"".equals(dictTypeId)) {
		// Object dictKey = super.get(dataItemKey);
		//
		// if (dictKey != null) {
		// Object dictValue = SaturnDictionaryManager.getInstance()
		// .getDictValue(dictTypeId, dictKey);
		//
		// this.put(strKey, dictValue);
		// return dictValue;
		// }
		// }
		// }

		return null;
	}

	/**
	 * 重写了Map的put方法，检查给定的键值是否被数据组件定义，是则添加数据；否则抛出异常对象
	 */
	public Object put(String key, Object value) {
		Object validValue = validate(key, value);

		if (key != null) {
			if (validValue instanceof String) {
				return super.put(key, ((String) validValue).trim());
			} else {
				return super.put(key, validValue);
			}
		}

		throw new IllegalArgumentException(
				"try to set saturndata with key \"null\"");
	}

	/**
	 * 获得指定键值的数据
	 * 
	 * @param key
	 * @return
	 */
	public String getString(String key) {
		return (String) super.get(key);
	}

	/**
	 * 向数据项添加键值对
	 * 
	 * @param key
	 * @param value
	 */
	public void setString(String key, String value) {
		if (value == null) {
			this.set(key, value);
		} else {
			this.set(key, value.trim());
		}
	}

	/**
	 * 获得数据项的字符串表示
	 */
	@Override
	public String toString() {
		StringBuffer stringBuffer = new StringBuffer().append("{");

		if (this.getSaturnDataInfo() != null) {

			for (String key : this.getSaturnDataInfo().keySet()) {
				stringBuffer.append("[").append(key).append("=").append(
						this.get(key)).append("], ");
			}
			stringBuffer.deleteCharAt(stringBuffer.length() - 1);
			stringBuffer.append("}\n");
		}

		return stringBuffer.toString();
	}

	/**
	 * 获得指定的属性的字典值
	 * 
	 * @param key
	 * @return
	 */
	public String getDictValue(String key) {
		Object dictCode = super.get(key);

		if (key != null) {
			IDataItem dataItem = this.dataInfo.getDataItem(key);

			if (dataItem != null) {
				String typeId = dataItem.getDictTypeId();

				if (typeId != null && !"".equals(typeId)) {
					return SaturnDictionaryManager.getInstance().getDictValue(
							typeId, dictCode);
				}
			}
		}

		return dictCode.toString();
	}

	/**
	 * 获得指定的属性的数字格式化后的值
	 * 
	 * @param key
	 * @return
	 */
	public String getNumberFormatValue(String key) {
		Object value = super.get(key);

		if (key != null) {
			IDataItem dataItem = this.dataInfo.getDataItem(key);

			if (dataItem != null) {
				String numberFormat = dataItem.getNumberFormat();

				if (numberFormat != null && !"".equals(numberFormat)) {
					DecimalFormat df = new DecimalFormat(numberFormat);

					try {
						if (value instanceof Number) {
							return df.format(((Number) value).doubleValue());
						} else {
							return df.format(new Double(value.toString()));
						}
					} catch (NumberFormatException e) {
						e.printStackTrace();
					}
				}
			}
		}

		return value.toString();
	}

	/**
	 * 获得指定的属性的时间格式化后的值
	 * 
	 * @param key
	 * @return
	 */
	public String getDatetimeFormatValue(String key) {
		Object value = super.get(key);

		if (key != null) {
			IDataItem dataItem = this.dataInfo.getDataItem(key);

			if (dataItem != null) {
				String datetimeFormat = dataItem.getDatetimeFormat();

				if (datetimeFormat != null && !"".equals(datetimeFormat)) {
					SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
							datetimeFormat);

					if (value instanceof java.util.Date
							|| value instanceof java.sql.Date) {
						return simpleDateFormat.format(value);
					}

					return simpleDateFormat.format(DateUtils.getDate(value
							.toString()));
				}
			}
		}

		return value.toString();
	}
}
